﻿using Aspose.Cells;
using Bentley.CifNET.Dgn;
using Bentley.CifNET.Geometry;
using Bentley.Collections;
using Bentley.DgnPlatformNET.Elements;
using Bentley.GeometryNET;
using Bentley.Internal.MstnPlatformNET;
using CheccCoverplateCulvertAssemble.Common;
using CheccCoverplateCulvertAssemble.Common.Http;
using CheccCoverplateCulvertAssemble.Common.Total;
using CheccCoverplateCulvertAssemble.Conmmon;
using CheccCoverplateCulvertAssemble.SlabCulvert;
using CheccCoverplateCulvertAssemble.Tools;
using CheccTexturePropertyGive;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static CheccTexturePropertyGive.SetCoverCulvertTexture;
using BIM = Bentley.Interop.MicroStationDGN;
namespace CheccCoverplateCulvertAssemble.Operation
{
    public class PlaceSlab
    {
        public PlaceSlab() { }
        public PlaceSlab(string leftModelName ,string leftDgnFilePath, string modelName, string dgnFilePath, string rightModelName, string rightDgnFilePath,DMatrix3d dMatrix3D,DPoint3d dPoint3D)
        {
            this.LeftModelName = leftModelName;
            this.LeftDgnFilePath = leftDgnFilePath; 
            this.ModelName = modelName;
            this.DgnFilePath = dgnFilePath;
            this.RightModelName = rightModelName;
            this.RightDgnFilePath = rightDgnFilePath;
            this.placeDMatrix3D = dMatrix3D;    
            this.placeDPoint3d = dPoint3D;  
        }
        /// <summary>
        /// 左侧斜盖板模型名
        /// </summary>
        private string LeftModelName { get; }
        /// <summary>
        /// 左侧斜盖板单元库全路径
        /// </summary>
        private string LeftDgnFilePath { get; }
        /// <summary>
        /// 正盖板模型名
        /// </summary>
        private string ModelName { get; }
        /// <summary>
        /// 正盖板单元库全路径
        /// </summary>
        private string DgnFilePath { get; }
        /// <summary>
        /// 右侧斜盖板模型名
        /// </summary>
        private string RightModelName { get; }
        /// <summary>
        /// 右侧斜盖板单元库全路径
        /// </summary>
        private string RightDgnFilePath { get; }

        /// <summary>
        /// 涵洞放置矩阵
        /// </summary>
        private DMatrix3d placeDMatrix3D { get; set; }
        /// <summary>
        /// 涵洞放置点
        /// </summary>
        private DPoint3d placeDPoint3d { get; set; }

        /// <summary>
        /// 是采用通用图放置盖板
        /// </summary>
        /// <param name="lengthOfPanelSubsection">盖板分段</param>
        /// <param name="sulvertSlope">涵底坡度</param>
        /// <param name="culvertGapWidth">涵身沉降缝宽度</param>
        /// <param name="leftAngle">左偏角</param>
        /// <param name="rightAngle">右偏角</param>
        /// <param name="piecePly">挡块高度</param>
        public void PlaceTiltSlab(List<double> lengthOfPanelSubsection ,double sulvertSlope, double culvertGapWidth,double leftAngle,double rightAngle,double piecePly, ConstructionMethod constructionMethod)
        {
            List<Element> elements = new List<Element>();   
            //距原点距离
            double zeroDistance = 0;
            for (int i = 0; i < lengthOfPanelSubsection.Count; i++)
            {
                if (i == 0 && leftAngle != 90)
                {
                    DTransform3d transT = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, 0, 1), Angle.FromDegrees(-90));
                    //Element cellEE = ImportCellElement(this.LeftModelName, this.LeftDgnFilePath, transT, Session.Instance.GetActiveDgnModel());
                    Element cellEE = InsertCellElement(this.LeftModelName, this.LeftDgnFilePath);
                    //AssignLevelToElement(cellEE, "涵洞盖板");
                    cellEE.ApplyTransform(new TransformInfo(transT));
                    if (leftAngle > 90)
                    {
                        DPoint3d mirrorPt = new DPoint3d(0, 1, 0) * GeneralBank.UorToMeters;
                        DTransform3d.TryMirrorPointToPoint(new DPoint3d(0, -1, 0) * GeneralBank.UorToMeters, mirrorPt, out DTransform3d mirrorTrans);
                        cellEE.ApplyTransform(new TransformInfo(mirrorTrans));
                    }

                    Angle angle = Angle.FromDegrees(Math.Atan(sulvertSlope) * 180 / Math.PI);
                    DTransform3d trans = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, -1, 0), angle);
                    double offsetZ = lengthOfPanelSubsection[i] * 0.01 * sulvertSlope - piecePly;
                    DPoint3d movePoint3d = new DPoint3d(lengthOfPanelSubsection[i] * 0.01, 0, offsetZ) * GeneralBank.UorToMeters;
                    trans.Translation = movePoint3d;
                    TransformInfo transformInfo = new TransformInfo(trans);
                    cellEE.ApplyTransform(transformInfo);
                    elements.Add(cellEE);
                    //工程数量
                    GetCellValue(this.LeftModelName, this.LeftDgnFilePath, cellEE);
                }
                else if (i == lengthOfPanelSubsection.Count - 1 && rightAngle != 90)
                {
                    DTransform3d transT = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, 0, 1), Angle.FromDegrees(90));
                    //Element cellEE = ImportCellElement(this.RightModelName, this.RightDgnFilePath, transT, Session.Instance.GetActiveDgnModel());
                    Element cellEE = InsertCellElement(this.RightModelName, this.RightDgnFilePath);
                    //AssignLevelToElement(cellEE, "涵洞盖板");
                    cellEE.ApplyTransform(new TransformInfo(transT));
                    if (rightAngle > 90)
                    {
                        DPoint3d mirrorPt = new DPoint3d(0, 1, 0) * GeneralBank.UorToMeters;
                        DTransform3d.TryMirrorPointToPoint(new DPoint3d(0, -1, 0) * GeneralBank.UorToMeters, mirrorPt, out DTransform3d mirrorTrans);
                        cellEE.ApplyTransform(new TransformInfo(mirrorTrans));
                    }

                    Angle angle = Angle.FromDegrees(Math.Atan(sulvertSlope) * 180 / Math.PI);
                    DTransform3d trans = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, -1, 0), angle);
                    double offsetZ = zeroDistance * sulvertSlope - piecePly;
                    DPoint3d movePoint3d = new DPoint3d(zeroDistance, 0, offsetZ) * GeneralBank.UorToMeters;
                    trans.Translation = movePoint3d;
                    TransformInfo transformInfo = new TransformInfo(trans);
                    cellEE.ApplyTransform(transformInfo);
                    elements.Add(cellEE);
                    //工程数量
                    GetCellValue(this.RightModelName, this.RightDgnFilePath, cellEE);
                }
                else 
                {
                    string cellName = this.ModelName;
                    if (constructionMethod == ConstructionMethod.CastInPlace)
                    {
                        cellName = "";
                        string[] names = this.ModelName.Split('_');
                        names[2] = (lengthOfPanelSubsection[i] * 0.01).ToString();
                        int index = 0;
                        while (index < names.Length) 
                        {
                            if (index == 0)
                            {
                                cellName += names[index];
                            }
                            else 
                            {
                                cellName += "_" + names[index];
                            }
                            index++;
                        }
                    }
                    double offsetZ = zeroDistance * sulvertSlope - piecePly;
                    DPoint3d movePoint3d = new DPoint3d(zeroDistance + culvertGapWidth / 2, 0, offsetZ) * GeneralBank.UorToMeters;
                    Angle angle = Angle.FromDegrees(Math.Atan(sulvertSlope) * 180 / Math.PI);
                    DTransform3d trans = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, -1, 0), angle);
                    trans.Translation = movePoint3d;
                    //Element cellEE = ImportCellElement(cellName, this.DgnFilePath, trans, Session.Instance.GetActiveDgnModel());
                    Element cellEE = InsertCellElement(cellName, this.DgnFilePath);
                    //AssignLevelToElement(cellEE, "涵洞盖板");
                    TransformInfo transformInfo = new TransformInfo(trans);
                    cellEE.ApplyTransform(transformInfo);
                    elements.Add(cellEE);
                    //工程数量
                    GetCellValue(cellName, this.DgnFilePath, cellEE);

                }
                zeroDistance += lengthOfPanelSubsection[i] * 0.01;
            }
            //涵底坡度对应角度
            Angle angle2 = Angle.FromDegrees(Math.Atan(sulvertSlope) * 180 / Math.PI);
            foreach (Element resultElement in elements)
            {
                //真实位置
                DTransform3d dTransform3d = new DTransform3d(this.placeDMatrix3D);
                dTransform3d.Translation = this.placeDPoint3d * GeneralBank.UorToMeters;
                TransformInfo dTransFormInfo = new TransformInfo(dTransform3d);
                resultElement.ApplyTransform(dTransFormInfo);
                //resultElement.AddToModel();
                resultElement.ReplaceInModel(resultElement);

                CommonData.Instance.ElementIds.Add(resultElement.ElementId.ToString());
            }
        }


        /// <summary>
        /// 否采用通用图放置盖板
        /// </summary>
        /// <param name="lengthOfPanelSubsection">盖板分段</param>
        /// <param name="sulvertSlope">涵底坡度</param>
        /// <param name="culvertGapWidth">涵身沉降缝宽度</param>
        /// <param name="leftAngle">左偏角</param>
        /// <param name="rightAngle">右偏角</param>
        /// <param name="piecePly">挡块高度</param>
        public void WhetherPlaceTiltSlab(List<double> lengthOfPanelSubsection, double sulvertSlope, double culvertGapWidth, double leftAngle, double rightAngle, double piecePly, ConstructionMethod constructionMethod)
        {
            List<Element> elements = new List<Element>();
            //距原点距离
            double zeroDistance = 0;
            for (int i = 0; i < lengthOfPanelSubsection.Count; i++)
            {
                if (i == 0 && leftAngle != 90)//左斜
                {
                    DTransform3d transT = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, 0, 1), Angle.FromDegrees(-90));
                    Element cellEE = CreateSlabCulvert.CreateSlopingCoverPlate(CommonData.Instance.CoverPlateParameter.LeftInclinedPlate.Length,
                        CommonData.Instance.CoverPlateParameter.LeftInclinedPlate.ShortSideLength ,
                        CommonData.Instance.CoverPlateParameter.LeftInclinedPlate.LongSideLength,
                        CommonData.Instance.CoverPlateParameter.LeftInclinedPlate.Thickness);

                    //AssignLevelToElement(cellEE, "涵洞盖板");
                    cellEE.ApplyTransform(new TransformInfo(transT));
                    if (leftAngle > 90)
                    {
                        DPoint3d mirrorPt = new DPoint3d(0, 1, 0) * GeneralBank.UorToMeters;
                        DTransform3d.TryMirrorPointToPoint(new DPoint3d(0, -1, 0) * GeneralBank.UorToMeters, mirrorPt, out DTransform3d mirrorTrans);
                        cellEE.ApplyTransform(new TransformInfo(mirrorTrans));
                    }

                    Angle angle = Angle.FromDegrees(Math.Atan(sulvertSlope) * 180 / Math.PI);
                    DTransform3d trans = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, -1, 0), angle);
                    double offsetZ = lengthOfPanelSubsection[i] * 0.01 * sulvertSlope - piecePly;
                    DPoint3d movePoint3d = new DPoint3d(lengthOfPanelSubsection[i] * 0.01, 0, offsetZ) * GeneralBank.UorToMeters;
                    trans.Translation = movePoint3d;
                    TransformInfo transformInfo = new TransformInfo(trans);
                    cellEE.ApplyTransform(transformInfo);
                    elements.Add(cellEE);
                }
                else if (i == lengthOfPanelSubsection.Count - 1 && rightAngle != 90)//右斜
                {
                    DTransform3d transT = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, 0, 1), Angle.FromDegrees(90));

                    Element cellEE = CreateSlabCulvert.CreateSlopingCoverPlate(CommonData.Instance.CoverPlateParameter.RightInclinedPlate.Length,
                        CommonData.Instance.CoverPlateParameter.RightInclinedPlate.ShortSideLength,
                        CommonData.Instance.CoverPlateParameter.RightInclinedPlate.LongSideLength ,
                        CommonData.Instance.CoverPlateParameter.RightInclinedPlate.Thickness);

                    //AssignLevelToElement(cellEE, "涵洞盖板");
                    cellEE.ApplyTransform(new TransformInfo(transT));
                    if (rightAngle > 90)
                    {
                        DPoint3d mirrorPt = new DPoint3d(0, 1, 0) * GeneralBank.UorToMeters;
                        DTransform3d.TryMirrorPointToPoint(new DPoint3d(0, -1, 0) * GeneralBank.UorToMeters, mirrorPt, out DTransform3d mirrorTrans);
                        cellEE.ApplyTransform(new TransformInfo(mirrorTrans));
                    } 

                    Angle angle = Angle.FromDegrees(Math.Atan(sulvertSlope) * 180 / Math.PI);
                    DTransform3d trans = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, -1, 0), angle);
                    double offsetZ = zeroDistance * sulvertSlope - piecePly;
                    DPoint3d movePoint3d = new DPoint3d(zeroDistance, 0, offsetZ) * GeneralBank.UorToMeters;
                    trans.Translation = movePoint3d;
                    TransformInfo transformInfo = new TransformInfo(trans);
                    cellEE.ApplyTransform(transformInfo);
                    elements.Add(cellEE);
                }
                else//正
                {
                    
                    double offsetZ = zeroDistance * sulvertSlope - piecePly;
                    DPoint3d movePoint3d = new DPoint3d(zeroDistance + culvertGapWidth / 2, 0, offsetZ) * GeneralBank.UorToMeters;
                    Angle angle = Angle.FromDegrees(Math.Atan(sulvertSlope) * 180 / Math.PI);
                    DTransform3d trans = DTransform3d.FromRotationAroundLine(DPoint3d.Zero, new DVector3d(0, -1, 0), angle);
                    trans.Translation = movePoint3d;

                    Element cellEE = CreateSlabCulvert.CreateStraightCoverPlate(CommonData.Instance.CoverPlateParameter.FrontPlate.Length,
                        lengthOfPanelSubsection[i] * 0.01,
                        CommonData.Instance.CoverPlateParameter.FrontPlate.FulcrumThickness,
                        CommonData.Instance.CoverPlateParameter.FrontPlate.MidspanThickness);

                    //AssignLevelToElement(cellEE, "涵洞盖板");
                    TransformInfo transformInfo = new TransformInfo(trans);
                    cellEE.ApplyTransform(transformInfo);
                    elements.Add(cellEE);

                }
                zeroDistance += lengthOfPanelSubsection[i] * 0.01;
            }
            //涵底坡度对应角度
            Angle angle2 = Angle.FromDegrees(Math.Atan(sulvertSlope) * 180 / Math.PI);

            SetCoverCulvertTexture setCoverCulvertTexture = new SetCoverCulvertTexture();
            foreach (Element resultElement in elements)
            {
                //真实位置
                DTransform3d dTransform3d = new DTransform3d(this.placeDMatrix3D);
                dTransform3d.Translation = this.placeDPoint3d * GeneralBank.UorToMeters;
                TransformInfo dTransFormInfo = new TransformInfo(dTransform3d);
                resultElement.ApplyTransform(dTransFormInfo);
                resultElement.AddToModel();
                CommonData.Instance.ElementIds.Add(resultElement.ElementId.ToString());

                //材质赋予
                if (resultElement.Equals(elements.First()) || resultElement.Equals(elements.Last()))
                {
                    setCoverCulvertTexture.CoverCulvertTexture(resultElement, CoverCulvertConstruction.CrookedSlab);
                }
                else
                {
                    setCoverCulvertTexture.CoverCulvertTexture(resultElement, CoverCulvertConstruction.PositiveSlab);
                }

                //工程数量
                string slabType = CommonData.Instance.CommomTotal.CoverPlateType == "预制" ? "预制盖板" : "现浇盖板";
                CheccCoverplateCulvertAssemble.FormColl.Assemble.SetTableData(slabType, "混凝土", GeneralHelpers.GetCSVDatas("正盖板")["混凝土等级"], SetCoverCulvertECProperty.GetVolume(resultElement, Bentley.MstnPlatformNET.InteropServices.Utilities.ComApp), "m³");
            }
        }


        public void GetCellValue(string celName, string fileName, Element element)
        {
            DgnDocument dgnDocument = DgnDocument.CreateForLocalFile(celName);
            DgnFileOwner dgnFileOwner = DgnFile.Create(dgnDocument, DgnFileOpenMode.ReadOnly);
            DgnFile dgnFile = dgnFileOwner.DgnFile;
            StatusInt statusInt;
            dgnFile.LoadDgnFile(out statusInt);
            ModelIndexCollection modelIndexCollection = dgnFile.GetModelIndexCollection();
            foreach (var item in modelIndexCollection)
            {
                if (item.Name == fileName)
                {
                    DgnModel dgnModel = dgnFile.LoadRootModelById(out statusInt, item.Id);
                    ModelElementsCollection modelElementsCollection = dgnModel.GetElements();
                    foreach (Element ele in modelElementsCollection)
                    {
                        if (ele.ElementType == MSElementType.Solid || ele.TypeName == "智能实体")
                        {
                            string slabType = CommonData.Instance.CommomTotal.CoverPlateType == "预制" ? "预制盖板" : "现浇盖板";
                            CheccCoverplateCulvertAssemble.FormColl.Assemble.SetTableData(slabType, "混凝土", GeneralHelpers.GetCSVDatas("正盖板")["混凝土等级"], SetCoverCulvertECProperty.GetVolume(element, Bentley.MstnPlatformNET.InteropServices.Utilities.ComApp), "m³");
                            break;
                        }
                    }
                    break;
                }
            }
        }



        /// <summary>
        /// 插入共享单元
        /// </summary>
        /// <param name="modelName">单元名</param>
        /// <param name="dgnFilePath">单元库全路径</param>
        /// <param name="transform3D"></param>
        /// <param name="targetModel"></param>
        /// <returns></returns>
        private Element ImportCellElement(string modelName, string dgnFilePath, DTransform3d transform3D, DgnModel targetModel)
        {
            DgnDocument document = DgnDocument.CreateForLocalFile(dgnFilePath);
            DgnFileOwner dgnFileOwner = DgnFile.Create(document, DgnFileOpenMode.ReadOnly);
            DgnFile dgnFile = dgnFileOwner.DgnFile;
            dgnFile.LoadDgnFile(out var openForWriteStatus);
            if (openForWriteStatus == StatusInt.Error)
            {
                return null;
            }

            ModelId modelId = dgnFile.FindModelIdByName(modelName);
            StatusInt errorDetails;
            DgnModel dgnModel = dgnFile.LoadRootModelById(out errorDetails, modelId);
            if (!(errorDetails == StatusInt.Error))
            {
                //CellHeaderElement cellHeaderElement = CellHeaderElement.CreateOrphanCellElement(targetModel, modelName, (from ele in dgnModel.GetElements()
                //                                                                                                         where ele.IsGraphics
                //                                                                                                         select ele).ToList());
                CellHeaderElement cellHeaderElement = new CellHeaderElement(targetModel, modelName,DPoint3d.Zero,DMatrix3d.Identity, (from ele in dgnModel.GetElements()
                                                                                                                                          where ele.IsGraphics
                                                                                                                                       select ele).ToList());
                AssignLevelToElement(cellHeaderElement, "涵洞盖板");
                TransformInfo transform = new TransformInfo(transform3D);
                transform.AnnotationScale = 1;
                cellHeaderElement.ApplyTransform(transform);
                //cellHeaderElement.AddToModel();
                return cellHeaderElement;
            }
            else
            {
                return null;
            }
        }
 

        public Element InsertShardCell(string cellName)
        {

            SharedCellDefinitionCollection sharedCellDefCol = Session.Instance.GetActiveDgnFile().GetNamedSharedCellDefinitions();
            SharedCellDefinitionElement sharedCellDef = null;
            foreach (var curDef in sharedCellDefCol)
            {
                if (curDef.CellName == cellName)
                {
                    sharedCellDef = curDef;
                    break;
                }
            }
            if (null == sharedCellDef)
                return null;
            SharedCellElement sharedCellEle = new SharedCellElement(Session.Instance.GetActiveDgnModel(),
                null, cellName, DPoint3d.Zero, DMatrix3d.Identity, new DPoint3d(1, 1, 1));
            sharedCellEle.SetDefinitionId(sharedCellDef.ElementId);
            sharedCellEle.AddToModel();
            return sharedCellEle;
        }

        public static Bentley.Interop.MicroStationDGN.Application ComApp = Bentley.MstnPlatformNET.InteropServices.Utilities.ComApp;
        public static Element InsertCellElement(string modelName, string dgnFilePath)
        {
            string celLibName = "";
            bool boo = ComApp.IsCellLibraryAttached;
            if (boo == true) celLibName = ComApp.AttachedCellLibrary.FullName;

            if (celLibName != dgnFilePath)
            {
                //    if (celLibName != "")
                //    {
                //        ComApp.CadInputQueue.SendCommand("DIALOG CELLMAINTENANCE");
                //        ComApp.CadInputQueue.SendCommand("DETACH LIBRARY");
                //        ComApp.CadInputQueue.SendMessageToApplication("MGDSHOOK", "CellMaint 0 " + celLibName + " 0 ");
                //        ComApp.CommandState.StartDefaultCommand();
                //    }
                ComApp.DetachCellLibrary(); 
                ComApp.AttachCellLibrary(dgnFilePath, Bentley.Interop.MicroStationDGN.MsdConversionMode.Prompt);
            }
            //Bentley.Interop.MicroStationDGN.CellLibrary activeLib = ComApp.AttachedCellLibrary;
            //Bentley.Interop.MicroStationDGN.Application MsApp = Bentley.MstnPlatformNET.InteropServices.Utilities.ComApp;
            BIM.Point3d ori = ComApp.Point3dZero();
            BIM.Point3d dp = new BIM.Point3d();
            BIM.Matrix3d matrix3D = new BIM.Matrix3d();

            //var ele = ComApp.CreateSharedCellElement3(modelName, ref ori,  false);
            var ele = ComApp.CreateSharedCellElement2(modelName, ref ori, ref dp, false, ref matrix3D);
            ComApp.ActiveModelReference.AddElement(ele);
            ComApp.ActiveDesignFile.Save();
            long id = ele.ID;
            Element element = Session.Instance.GetActiveDgnModel().FindElementById(new ElementId(ref id));
            return element;
        }


        //赋予图层
        private void AssignLevelToElement(Element element, string levelName)
        {
            var elementPropertiesSetter = new ElementPropertiesSetter();
            var levelId = CreateLevelByName(levelName);
            elementPropertiesSetter.SetLevel((LevelId)levelId);
            elementPropertiesSetter.Apply(element);
        }
        private LevelId? CreateLevelByName(string levelName)
        {
            FileLevelCache fileLevelCache = Session.Instance.GetActiveDgnFile().GetLevelCache();
            fileLevelCache.Write();
            LevelHandle levelHandle = fileLevelCache.GetLevelByName(levelName);
            if (!levelHandle.IsValid)
            {
                EditLevelHandle editLevelHandle = fileLevelCache.CreateLevel(levelName);
                fileLevelCache.Write();
                return editLevelHandle.LevelId;
            }
            return levelHandle.LevelId;
        }
    }
}
